package com.insight.modules.system.controller;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.XML;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yuanqiao.insight.acore.depart.entity.SysDepart;
import com.yuanqiao.insight.acore.system.service.ISysDictService;
import com.yuanqiao.insight.common.constant.CommonConstant;
import com.yuanqiao.insight.common.util.common.LocalCacheUtils;
import com.yuanqiao.insight.common.util.common.RedisUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.util.Strings;
import org.apache.shiro.SecurityUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import com.insight.common.api.vo.Result;
import com.insight.common.aspect.annotation.MPAccessToken;
import com.insight.common.constant.CacheConstant;
import com.insight.common.constant.MPConstant;
import com.insight.common.system.api.ISysBaseAPI;
import com.insight.common.system.util.JwtUtil;
import com.insight.common.system.vo.LoginUser;
import com.insight.common.util.*;
import com.insight.common.util.encryption.EncryptedString;
import com.insight.modules.base.service.BaseCommonService;
import com.insight.modules.system.entity.SysLog;
import com.insight.modules.system.entity.SysPermission;
import com.insight.modules.system.entity.SysTerminalUser;
import com.insight.modules.system.entity.SysUsers;
import com.insight.modules.system.mapper.SysTerminalUserMapper;
import com.insight.modules.system.mapper.SysUserMapper;
import com.insight.modules.system.model.AutoLoginModel;
import com.insight.modules.system.model.SysLoginModel;
import com.insight.modules.system.service.ISysDepartService;
import com.insight.modules.system.service.ISysLogService;
import com.insight.modules.system.service.ISysPermissionService;
import com.insight.modules.system.service.ISysUserService;
import com.insight.modules.system.util.Base64Util;
import com.insight.modules.system.util.RandImageUtil;
import com.insight.modules.system.vo.UkeyVo;
import com.insight.modules.umpPwdManage.entity.UmpPwdManage;
import com.insight.modules.umpPwdManage.mapper.UmpPwdManageMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author scott
 * @since 2018-12-17
 */
@RestController
@RequestMapping("/sys")
@Api(tags = "用户登录")
@Slf4j
public class LoginController {
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private ISysBaseAPI sysBaseAPI;
    @Autowired
    private ISysLogService logService;
    @Autowired
    private RedisUtils redisUtil;
    @Autowired
    private ISysDepartService sysDepartService;
    @Autowired
    private ISysDictService sysDictService;
    @Resource
    private BaseCommonService baseCommonService;
    @Autowired
    private UmpPwdManageMapper umpPwdManageMapper;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ISysPermissionService sysPermissionService;
    @Autowired
    private SysTerminalUserMapper sysTerminalUserMapper;

    LocalCacheUtils cacheUtils = LocalCacheUtils.getInstance();
    @Value("${cas.logout}")
    private String logout;
    //    @Value(value = "${insight.isThreePowers}")
    private int isThreePowers;
    //    @Value("${Ukey.ip}")
    private String ip;
    //    @Value("${Ukey.post}")
    private String post;
    @Autowired
    private JwtUtil jwtUtil;

    private static final String BASE_CHECK_CODES = "qwertyuipkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM23456789";


    @RequestMapping(value = "/isThreePowers")
    public Object isThreePowers() {
        isThreePowers = Integer.parseInt((String) cacheUtils.getValueByKey(CommonConstant.DATA_DICT_KEY + "insight_threePowers_isEnable"));
        if (isThreePowers == 1) {
            LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
            if ("root".equals(loginUser.getUsername())) {
                isThreePowers = 0;
            }
        }


        return Result.OK(isThreePowers);
    }

    @ApiOperation("登录接口")
    @PostMapping(value = "/login")
    public Result<JSONObject> login(@RequestBody SysLoginModel sysLoginModel, HttpServletRequest request) throws ParseException, SocketException, UnknownHostException {
        Result<JSONObject> result = new Result<>();
        UmpPwdManage allPwdManage = umpPwdManageMapper.findAllPwdManage();   // 此处查出该系统的所有规则
        String key = "locks:" + sysLoginModel.getUsername();
        int count = 1;
        String ip = getIp(request);
        if (CommonConstant.LOCAL_IP.equals(ip)) {
            InetAddress addr = InetAddress.getLocalHost();
            ip = addr.getHostAddress();
        }

        if (StringUtils.isNotEmpty(allPwdManage.getStartIp()) && StringUtils.isNotEmpty(allPwdManage.getStopIp())) {
            String ipParagraph = allPwdManage.getStartIp() + "-" + allPwdManage.getStopIp();
            if (!ipIsInRange(ip, ipParagraph)) {
                result.error500("不在可登录的ip范围内");
                return result;
            }
        }

        if (StringUtils.isNotEmpty(allPwdManage.getStartTime()) && StringUtils.isNotEmpty(allPwdManage.getStopTime())) {
            if (!getLoginTime(allPwdManage)) {
                result.error500("不在可登录的时间范围内");
                return result;
            }
        }
        if (redisUtil.hasKey(key)) {
            count = (int) redisUtil.get(key);
        }
        SysUsers user = sysUserService.getOne(new QueryWrapper<SysUsers>()
                .eq("username", sysLoginModel.getUsername())
                .eq("del_flag", "0"));
        if (count >= Integer.parseInt(allPwdManage.getErrorNum())) {
            Date currentTime = new Date();
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String dateString = formatter.format(currentTime);
            sysUserMapper.updateLock(1, dateString, sysLoginModel.getUsername());
        }
        if (null == user) {
            result.error500("用户不存在");
            return result;
        } else if (user.getLocks() == 1) {
            result.error500("用户已被锁定，将在" + allPwdManage.getUnLock() + "分钟后自动解锁，或者联系安全保密管理员解锁");
            return result;
        }
        String username = sysLoginModel.getUsername();
        String password = sysLoginModel.getPassword();
        if (!checkCode(result, sysLoginModel)) {
            return result;
        }
        //1. 校验用户是否有效
        result = sysUserService.checkUserIsEffective(user);
        if (!result.isSuccess()) {
            return result;
        }
        Optional<Object> optional = Optional.ofNullable(cacheUtils.getValueByKey(CommonConstant.DATA_DICT_KEY + "login_setting_single_online"));
        boolean isCheckOnline = Integer.parseInt(String.valueOf(optional.orElse("0"))) == 1;
        boolean isOnline = isCheckOnline && isOnline(username);
        //2. 校验用户名或密码是否正确
        String userpassword = PasswordUtil.encrypt(username, password, user.getSalt());
        String syspassword = user.getPassword();
        if (!syspassword.equals(userpassword)) {
            result.error500("用户名或密码错误");
            if (Boolean.FALSE.equals(redisTemplate.hasKey(key))) {
                redisTemplate.opsForValue().set(key, 1);
                redisTemplate.expire(key, Long.parseLong(allPwdManage.getUnLock()) * 60, TimeUnit.SECONDS);
            } else {
                redisTemplate.opsForValue().increment(key, 1);
                redisTemplate.expire(key, Long.parseLong(allPwdManage.getUnLock()) * 60, TimeUnit.SECONDS);
            }

            return result;
        }

        //用户登录信息
        userInfo(user, result, allPwdManage, null);

        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(user, loginUser);
        JSONObject result1 = (JSONObject) result.getResult();
        result1.put("isOline", isOnline);
        String multi_depart = result1.getString("multi_depart");
        SysTerminalUser byUserName = sysTerminalUserMapper.selectOne(new QueryWrapper<SysTerminalUser>().eq("user_name", sysLoginModel.getUsername()));
        if (byUserName != null) {
            result1.put("terminalInfo", byUserName.getUniqueCode());
        } else {
            result1.put("terminalInfo", "");
        }
        result.setResult(result1);
        if (!"3".equals(multi_depart)) {
            baseCommonService.addLog("用户名: " + loginUser.getRealname() + ",登录成功！", CommonConstant.LOG_TYPE_1, null, loginUser);
        }
        return result;
    }

    @ApiOperation("运维助手登录接口")
    @PostMapping(value = "/terminalLogin")
    public Result<JSONObject> terminalLogin(@RequestBody SysLoginModel sysLoginModel, HttpServletRequest request) throws ParseException, SocketException, UnknownHostException {
        Result<JSONObject> result = new Result<JSONObject>();
        UmpPwdManage allPwdManage = umpPwdManageMapper.findAllPwdManage();   // 此处查出该系统的所有规则
        String key = "locks:" + sysLoginModel.getUsername();
        int count = 1;

        if (StringUtils.isEmpty(sysLoginModel.getHostName())) {
            result.error500("未携带当前终端标识！");
            return result;
        }
        SysTerminalUser byUserName = sysTerminalUserMapper.selectOne(new QueryWrapper<SysTerminalUser>().eq("user_name", sysLoginModel.getUsername()));
        if (byUserName != null) {
            if (!byUserName.getUniqueCode().equals(sysLoginModel.getHostName())) {
                result.error500("当前用户已绑定其它终端！");
                return result;
            }
        }
        SysTerminalUser byHostName = sysTerminalUserMapper.selectOne(new QueryWrapper<SysTerminalUser>().eq("unique_code", sysLoginModel.getHostName()));
        if (byHostName != null) {
            if (!byHostName.getUserName().equals(sysLoginModel.getUsername())) {
                result.error500("当前终端已被其它用户绑定！");
                return result;
            }
        }


        String ip = getIp(request);
        if (CommonConstant.LOCAL_IP.equals(ip)) {
            InetAddress addr = InetAddress.getLocalHost();
            ip = addr.getHostAddress();
        }
        if (StringUtils.isNotEmpty(allPwdManage.getStartIp()) && StringUtils.isNotEmpty(allPwdManage.getStopIp())) {
            String ipParagraph = allPwdManage.getStartIp() + "-" + allPwdManage.getStopIp();
            if (!ipIsInRange(ip, ipParagraph)) {
                result.error500("不在可登录的ip范围内");
                return result;
            }
        }


        if (StringUtils.isNotEmpty(allPwdManage.getStartTime()) && StringUtils.isNotEmpty(allPwdManage.getStopTime())) {
            if (!getLoginTime(allPwdManage)) {
                result.error500("不在可登录的时间范围内");
                return result;
            }
        }

        if (redisTemplate.hasKey(key)) {
            count = (int) redisTemplate.opsForValue().get(key);
        }
        if (allPwdManage != null) {
            if (count >= Integer.parseInt(allPwdManage.getErrorNum())) {
                Date currentTime = new Date();
                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String dateString = formatter.format(currentTime);
                sysUserMapper.updateLock(1, dateString, sysLoginModel.getUsername());
            }
            SysUsers user = sysUserService.getOne(new QueryWrapper<SysUsers>().eq("username", sysLoginModel.getUsername()));
            if (null == user) {
                result.error500("用户不存在");
                return result;
            } else if (user.getLocks() == 1) {
                result.error500("用户已被锁定，将在" + allPwdManage.getUnLock() + "分钟后自动解锁，或者联系安全保密管理员解锁");
                return result;
            }
        }
        String username = sysLoginModel.getUsername();
        String password = sysLoginModel.getPassword();
        if (!checkCode(result, sysLoginModel)) {
            return result;
        }
        //update-end-author:taoyan date:20190828 for:校验验证码

        //1. 校验用户是否有效
        //update-begin-author:wangshuai date:20200601 for: 登录代码验证用户是否注销bug，if条件永远为false
        LambdaQueryWrapper<SysUsers> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUsers::getUsername, username);
        SysUsers sysUser = sysUserService.getOne(queryWrapper);
        //update-end-author:wangshuai date:20200601 for: 登录代码验证用户是否注销bug，if条件永远为false
        result = sysUserService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }
        //2. 校验用户名或密码是否正确
        String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
        String syspassword = sysUser.getPassword();
        if (!syspassword.equals(userpassword)) {
            result.error500("用户名或密码错误");
            if (Boolean.FALSE.equals(redisTemplate.hasKey(key))) {
                redisTemplate.opsForValue().set(key, 1);
                redisTemplate.expire(key, Long.parseLong(allPwdManage.getUnLock()) * 60, TimeUnit.SECONDS);
            } else {
                redisTemplate.opsForValue().increment(key, 1);
                redisTemplate.expire(key, Long.parseLong(allPwdManage.getUnLock()) * 60, TimeUnit.SECONDS);
            }

            return result;
        }

        //用户登录信息
        userInfo(sysUser, result, allPwdManage, null);

        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(sysUser, loginUser);
        JSONObject result1 = (JSONObject) result.getResult();
        String multi_depart = result1.getString("multi_depart");
        if (byUserName != null) {
            result1.put("terminalInfo", byUserName.getUniqueCode());
        } else {
            result1.put("terminalInfo", "");
        }
        result.setResult(result1);
        if (!"3".equals(multi_depart)) {
            baseCommonService.addLog("用户名: " + loginUser.getRealname() + ",登录成功！", CommonConstant.LOG_TYPE_1, null, loginUser);
        }
        return result;
    }

    @ApiOperation("运维助手自动登录接口")
    @PostMapping(value = "/terminalAutoLogin")
    public Result<JSONObject> terminalAutoLogin(@RequestBody SysLoginModel sysLoginModel, HttpServletRequest request) throws ParseException, SocketException, UnknownHostException {
        Result<JSONObject> result = new Result<JSONObject>();
        UmpPwdManage allPwdManage = umpPwdManageMapper.findAllPwdManage();   // 此处查出该系统的所有规则
        String key = "locks:" + sysLoginModel.getUsername();
        int count = 1;

        if (StringUtils.isEmpty(sysLoginModel.getHostName())) {
            result.error500("未携带当前终端标识！");
            return result;
        }
        SysTerminalUser byUserName = sysTerminalUserMapper.selectOne(new QueryWrapper<SysTerminalUser>().eq("user_name", sysLoginModel.getUsername()));
        if (byUserName != null) {
            if (!byUserName.getUniqueCode().equals(sysLoginModel.getHostName())) {
                result.error500("当前用户已绑定其它终端！");
                return result;
            }
        }
        SysTerminalUser byHostName = sysTerminalUserMapper.selectOne(new QueryWrapper<SysTerminalUser>().eq("unique_code", sysLoginModel.getHostName()));
        if (byHostName != null) {
            if (!byHostName.getUserName().equals(sysLoginModel.getUsername())) {
                result.error500("当前终端已被其它用户绑定！");
                return result;
            }
        }


        String ip = getIp(request);
        if (CommonConstant.LOCAL_IP.equals(ip)) {
            InetAddress addr = InetAddress.getLocalHost();
            ip = addr.getHostAddress();
        }
        if (StringUtils.isNotEmpty(allPwdManage.getStartIp()) && StringUtils.isNotEmpty(allPwdManage.getStopIp())) {
            String ipParagraph = allPwdManage.getStartIp() + "-" + allPwdManage.getStopIp();
            if (!ipIsInRange(ip, ipParagraph)) {
                result.error500("不在可登录的ip范围内");
                return result;
            }
        }


        if (StringUtils.isNotEmpty(allPwdManage.getStartTime()) && StringUtils.isNotEmpty(allPwdManage.getStopTime())) {
            if (!getLoginTime(allPwdManage)) {
                result.error500("不在可登录的时间范围内");
                return result;
            }
        }

        if (redisTemplate.hasKey(key)) {
            count = (int) redisTemplate.opsForValue().get(key);
        }
        if (allPwdManage != null) {
            if (count >= Integer.parseInt(allPwdManage.getErrorNum())) {
                Date currentTime = new Date();
                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String dateString = formatter.format(currentTime);
                sysUserMapper.updateLock(1, dateString, sysLoginModel.getUsername());
            }
            SysUsers user = sysUserService.getOne(new QueryWrapper<SysUsers>().eq("username", sysLoginModel.getUsername()));
            if (null == user) {
                result.error500("用户不存在");
                return result;
            } else if (user.getLocks() == 1) {
                result.error500("用户已被锁定，将在" + allPwdManage.getUnLock() + "分钟后自动解锁，或者联系安全保密管理员解锁");
                return result;
            }
        }

        //1. 校验用户是否有效
        String username = sysLoginModel.getUsername();
        SysUsers sysUser = sysUserService.getUserByName(username);
        result = sysUserService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }

        //用户登录信息
        userInfo(sysUser, result, allPwdManage, null);

        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(sysUser, loginUser);
        JSONObject result1 = (JSONObject) result.getResult();
        String multi_depart = result1.getString("multi_depart");
        if (byUserName != null) {
            result1.put("terminalInfo", byUserName.getUniqueCode());
        } else {
            result1.put("terminalInfo", "");
        }
        result.setResult(result1);
        if (!"3".equals(multi_depart)) {
            baseCommonService.addLog("用户名: " + loginUser.getRealname() + ",登录成功！", CommonConstant.LOG_TYPE_1, null, loginUser);
        }
        return result;
    }


    @ApiOperation("自动登录接口")
    @RequestMapping(value = "/autoLogin", method = RequestMethod.POST)
    public Result<JSONObject> autoLogin(@RequestBody AutoLoginModel autoLoginModel) {
        Result<JSONObject> result = new Result<>();

        // 1. 校验必要参数
        if (Strings.isBlank(autoLoginModel.getAusername())) {
            result.setSuccess(false);
            result.setMessage("ausername未知");
            return result;
        }
        if (Strings.isBlank(autoLoginModel.getAkey())) {
            result.setSuccess(false);
            result.setMessage("akey未知");
            return result;
        }
        if (Strings.isBlank(autoLoginModel.getPath())) {
            result.setSuccess(false);
            result.setMessage("path未知");
            return result;
        }

        //  防御性拷贝：立即提取并保存不可变副本
        String username = autoLoginModel.getAusername();
        String akey = autoLoginModel.getAkey();
        String path = autoLoginModel.getPath(); // <--- 提取为局部变量

        // 2. 用户合法性检查
        SysUsers sysUsers = sysUserService.getUserByName(username);
        result = sysUserService.checkUserIsEffective(sysUsers);
        if (!result.isSuccess()) {
            return result;
        }

        // 3. 密码校验
        String newPassword = MD5Util.MD5Encode(sysUsers.getPassword(), "utf-8");
        if (!newPassword.equals(akey)) { // 使用拷贝后的 akey
            result.setSuccess(false);
            result.setMessage("akey无效");
            return result;
        }

        // 4. 权限菜单校验（使用拷贝后的 path）
        SysPermission sysPermission = sysPermissionService.queryByUrl(path);
        if (sysPermission == null) {
            result.setSuccess(false);
            result.setMessage("未获取到path对应的菜单");
            return result;
        }

        // 5. 设置用户信息
        userInfo(sysUsers, result, null, sysPermission.getPlatformType());

        // 6. 登录日志记录
        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(sysUsers, loginUser);
        JSONObject resultData = (JSONObject) result.getResult();
        String multi_depart = resultData.getString("multi_depart");
        if (!"3".equals(multi_depart)) {
            baseCommonService.addLog("用户名: " + loginUser.getRealname() + ",登录成功！", CommonConstant.LOG_TYPE_1, null, loginUser);
        }

        return result;
    }

    @ApiOperation("生成第三方登录授权key")
    @RequestMapping(value = "/generateKey", method = RequestMethod.GET)
    public Result<JSONObject> generateKey(String userId) {
        Result<JSONObject> result = new Result<JSONObject>();
        SysUsers sysUsers = sysUserService.getById(userId);
        if (sysUsers == null) {
            result.setSuccess(false);
            result.setMessage("未获取到path对应的菜单");
            return result;
        }
        result.setResult(MD5Util.MD5Encode(sysUsers.getPassword(), "utf-8"));
        return result;
    }

    private Boolean checkCode(Result<JSONObject> result, SysLoginModel sysLoginModel) {
        String captcha = sysLoginModel.getCaptcha();
        if (captcha == null) {
            result.error500("验证码无效");
            return false;
        }
        String lowerCaseCaptcha = captcha.toLowerCase();
        String realKey = MD5Util.MD5Encode(lowerCaseCaptcha + sysLoginModel.getCheckKey(), "utf-8");
        Object checkCode = redisUtil.get(realKey);
        //当进入登录页时，有一定几率出现验证码错误 #1714
        if (checkCode == null || !checkCode.toString().equals(lowerCaseCaptcha)) {
            result.error500("验证码错误");
            return false;
        }
        return true;
    }


    @ApiOperation("获取token")
    @PostMapping(value = "/getToken")
    public Result<JSONObject> getToken(HttpServletRequest request) throws ParseException, SocketException, UnknownHostException, InterruptedException {
        Result<JSONObject> result = new Result<>();
        if (request == null) {
            return result.error500("请求对象为空");
        }
        String authorization = request.getHeader("Authorization");
        if (StringUtils.isBlank(authorization)) {
            return result.error500("认证信息不存在");
        }
        try {
            if (!authorization.startsWith("Basic ")) {
                return result.error500("认证类型错误");
            }
            final String encode = authorization.substring(6);
            if (StringUtils.isBlank(encode)) {
                return result.error500("认证信息为空");
            }
            final String decode = Base64.decodeStr(encode, CharsetUtil.CHARSET_UTF_8);
            final String[] uAndP = decode.split(":");
            if (uAndP.length < 2 || StringUtils.isBlank(uAndP[0]) || StringUtils.isBlank(uAndP[1])) {
                return result.error500("用户名或密码不能为空");
            }
            String username = uAndP[0];
            String password = uAndP[1];
            LambdaQueryWrapper<SysUsers> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SysUsers::getUsername, username);
            SysUsers sysUser = sysUserService.getOne(queryWrapper);
            if (sysUserService == null || sysUser == null) {
                return result.error500("用户不存在");
            }
            result = sysUserService.checkUserIsEffective(sysUser);
            if (!result.isSuccess()) {
                return result;
            }
            String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
            String syspassword = sysUser.getPassword();
            if (syspassword == null || !syspassword.equals(userpassword)) {
                result.error500("用户名或密码错误");
                return result;
            }
            String newAuthorization = jwtUtil.sign(username, password);
            if (newAuthorization == null) {
                return result.error500("令牌生成失败");
            }
            if (redisUtil != null) {
                redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + newAuthorization, newAuthorization, jwtUtil.getTime());
            }
            result.setResult(newAuthorization);
            return result;
        } catch (Exception e) {
            return result.error500("认证出错, " + e.getMessage());
        }
    }

    // 查询出上次登录时间到现在时间与系统中对比，返回结果
    public boolean getUpdateTime(UmpPwdManage allPwdManage, String userName) {
        long i = 86400000; // 毫秒
        long time = 0L; // 老用户最后操作日志的时间 或 未开启三员情况下的新用户的添加时间（毫秒）

        QueryWrapper<SysLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("log_type", 3);
        queryWrapper.eq("userid", userName);
        // queryWrapper.like("log_content", "成功！");
        queryWrapper.orderByDesc("create_time");
        String sql = "limit " + "0" + ",1";
        queryWrapper.last(sql);
        SysLog userLog = logService.getOne(queryWrapper);
        isThreePowers = Integer.parseInt(String.valueOf(Optional.ofNullable(cacheUtils.getValueByKey(CommonConstant.DATA_DICT_KEY + "insight_threePowers_isEnable")).orElse("0")));
        if (userLog == null) {
            if (isThreePowers == 0) {
                SysUsers userByName = sysUserService.getUserByName(userName);
                if (userByName != null) {
                    time = userByName.getCreateTime().getTime();
                } else {
                    return false;
                }
            } else {
                return false;
            }
        } else {
            time = userLog.getCreateTime().getTime();
        }
        long l = System.currentTimeMillis(); // 当前时间 毫秒
        long lastTime = allPwdManage.getUpdateTimes() * i;  // 中间这几天的毫秒
        // 相减，来判断是否过期
        // 超过系统设定时间
        return l - time < lastTime;
    }

    public boolean Ukey(UmpPwdManage allPwdManage, String userName) {
        return true;
    }


    public boolean getLoginTime(UmpPwdManage allPwdManage) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");

        Date startTime = sdf.parse(allPwdManage.getStartTime());

        Date stopTime = sdf.parse(allPwdManage.getStopTime());

        Date loginTime = sdf.parse(sdf.format(new Date()));

        if (loginTime.after(startTime) && loginTime.before(stopTime)) {
//            System.out.println("在两个时间中间");
            return true;

        } else {
//            System.out.println("时间错过");
            return false;
        }
    }


    /**
     * 退出登录
     *
     * @param request
     * @param response
     * @return
     */

    @RequestMapping(value = "/logout")
    public Object logout(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
        //用户退出逻辑
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        if (oConvertUtils.isEmpty(token)) {
            return Result.error("退出登录失败！");
        }
        String username = JwtUtil.getUsername(token);
        LoginUser sysUser = sysBaseAPI.getUserByName(username);
        if (sysUser != null) {
            //update-begin--Author:wangshuai  Date:20200714  for：登出日志没有记录人员
            baseCommonService.addLog("用户名: " + sysUser.getRealname() + ",退出成功！", CommonConstant.LOG_TYPE_1, null, sysUser);
            //update-end--Author:wangshuai  Date:20200714  for：登出日志没有记录人员
            log.info(" 用户名:  " + sysUser.getRealname() + ",退出成功！ ");
            //清空用户登录Token缓存
            redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + token);
            //清空用户登录Shiro权限缓存
            redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + sysUser.getId());
            //清空用户的缓存信息（包括部门信息），例如sys:cache:user::<username>
            redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername()));
            //调用shiro的logout
            SecurityUtils.getSubject().logout();
            session.invalidate();
            // return Result.ok("退出登录成功！");

            return "redirect:" + logout;  //此处是cas重定向

        } else {
            return Result.error("Token无效!");
        }
    }

    /**
     * 获取访问量
     *
     * @return
     */
    @ApiOperation("获取访问量")
    @GetMapping("loginfo")
    public Result<JSONObject> loginfo() {
        Result<JSONObject> result = new Result<JSONObject>();
        JSONObject obj = new JSONObject();
        //update-begin--Author:zhangweijian  Date:20190428 for：传入开始时间，结束时间参数
        // 获取一天的开始和结束时间
        Calendar calendar = new GregorianCalendar();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Date dayStart = calendar.getTime();
        calendar.add(Calendar.DATE, 1);
        Date dayEnd = calendar.getTime();
        // 获取系统访问记录
        Long totalVisitCount = logService.findTotalVisitCount();
        obj.put("totalVisitCount", totalVisitCount);
        Long todayVisitCount = logService.findTodayVisitCount(dayStart, dayEnd);
        obj.put("todayVisitCount", todayVisitCount);
        Long todayIp = logService.findTodayIp(dayStart, dayEnd);
        //update-end--Author:zhangweijian  Date:20190428 for：传入开始时间，结束时间参数
        obj.put("todayIp", todayIp);
        result.setResult(obj);
        result.success("登录成功");
        return result;
    }

    /**
     * 获取访问量
     *
     * @return
     */
    @GetMapping("visitInfo")
    public Result<List<Map<String, Object>>> visitInfo() {
        Result<List<Map<String, Object>>> result = new Result<List<Map<String, Object>>>();
        Calendar calendar = new GregorianCalendar();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        Date dayEnd = calendar.getTime();
        calendar.add(Calendar.DAY_OF_MONTH, -7);
        Date dayStart = calendar.getTime();
        List<Map<String, Object>> list = logService.findVisitCount(dayStart, dayEnd);
        result.setResult(oConvertUtils.toLowerCasePageList(list));
        return result;
    }


    /**
     * 登陆成功选择用户当前部门
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "/selectDepart", method = RequestMethod.PUT)
    public Result<JSONObject> selectDepart(@RequestBody SysUsers user) {
        Result<JSONObject> result = new Result<JSONObject>();
        String username = user.getUsername();
        if (oConvertUtils.isEmpty(username)) {
            LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
            username = sysUser.getUsername();
        }
        String orgCode = user.getOrgCode();
        this.sysUserService.updateUserDepart(username, orgCode);
        SysUsers sysUser = sysUserService.getUserByName(username);
        JSONObject obj = new JSONObject();
        obj.put("userInfo", sysUser);
        result.setResult(obj);
        return result;
    }

    /**
     * 短信登录接口
     *
     * @param jsonObject
     * @return
     */
    @PostMapping(value = "/sms")
    public Result<String> sms(@RequestBody JSONObject jsonObject) {
        Result<String> result = new Result<String>();
        String mobile = jsonObject.get("mobile").toString();
        //手机号模式 登录模式: "2"  注册模式: "1"
        String smsmode = jsonObject.get("smsmode").toString();
        log.info(mobile);
        if (oConvertUtils.isEmpty(mobile)) {
            result.setMessage("手机号不允许为空！");
            result.setSuccess(false);
            return result;
        }
        Object object = redisUtil.get(mobile);
        if (object != null) {
            result.setMessage("验证码10分钟内，仍然有效！");
            result.setSuccess(false);
            return result;
        }

        //随机数
        String captcha = RandomUtil.randomNumbers(6);
        JSONObject obj = new JSONObject();
        obj.put("code", captcha);
        try {
            boolean b = false;
            //注册模板
            if (CommonConstant.SMS_TPL_TYPE_1.equals(smsmode)) {
                SysUsers sysUser = sysUserService.getUserByPhone(mobile);
                if (sysUser != null) {
                    result.error500(" 手机号已经注册，请直接登录！");
                    baseCommonService.addLog("手机号已经注册，请直接登录！", CommonConstant.LOG_TYPE_1, null);
                    return result;
                }
                b = DySmsHelper.sendSms(mobile, obj, DySmsEnum.REGISTER_TEMPLATE_CODE);
            } else {
                //登录模式，校验用户有效性
                //TODO::有趣
                SysUsers sysUser = sysUserService.getUserByPhone(mobile);
                Result<JSONObject> r = sysUserService.checkUserIsEffective(sysUser);
                if (!r.isSuccess()) {
                    String message = r.getMessage();
                    if ("该用户不存在，请注册".equals(message)) {
                        result.error500("该用户不存在或未绑定手机号");
                    }
                    return result;
                }

                /**
                 * smsmode 短信模板方式  0 .登录模板、1.注册模板、2.忘记密码模板
                 */
                if (CommonConstant.SMS_TPL_TYPE_0.equals(smsmode)) {
                    //登录模板
                    b = DySmsHelper.sendSms(mobile, obj, DySmsEnum.LOGIN_TEMPLATE_CODE);
                } else if (CommonConstant.SMS_TPL_TYPE_2.equals(smsmode)) {
                    //忘记密码模板
                    b = DySmsHelper.sendSms(mobile, obj, DySmsEnum.FORGET_PASSWORD_TEMPLATE_CODE);
                }
            }

            if (b == false) {
                result.setMessage("短信验证码发送失败,请稍后重试");
                result.setSuccess(false);
                return result;
            }
            //验证码10分钟内有效
            redisUtil.set(mobile, captcha, 600);
            //update-begin--Author:scott  Date:20190812 for：issues#391
            //result.setResult(captcha);
            //update-end--Author:scott  Date:20190812 for：issues#391
            result.setSuccess(true);

        } catch (ClientException e) {
            e.printStackTrace();
            result.error500(" 短信接口未配置，请联系管理员！");
            return result;
        }
        return result;
    }


    /**
     * 手机号登录接口
     *
     * @param jsonObject
     * @return
     */
    @ApiOperation("手机号登录接口")
    @PostMapping("/phoneLogin")
    public Result<JSONObject> phoneLogin(@RequestBody JSONObject jsonObject) {
        Result<JSONObject> result = new Result<JSONObject>();
        String phone = jsonObject.getString("mobile");

        //校验用户有效性
        SysUsers sysUser = sysUserService.getUserByPhone(phone);
        result = sysUserService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }

        String smscode = jsonObject.getString("captcha");
        Object code = redisUtil.get(phone);
        if (!smscode.equals(code)) {
            result.setMessage("手机验证码错误");
            return result;
        }
        //用户信息
        userInfo(sysUser, result, null, null);
        //添加日志
        baseCommonService.addLog("用户名: " + sysUser.getUsername() + ",登录成功！", CommonConstant.LOG_TYPE_1, null);

        return result;
    }

    /**
     * 获取微信用户手机号
     *
     * @param code
     * @return
     */
    @GetMapping("/getPhoneNumber/{code}")
    public Result<JSONObject> getPhoneNumber(@PathVariable("code") String code) {
        Result<JSONObject> result = new Result<>();

        return result;
    }


    /**
     * 小程序使用手机号登录
     * 小程序获取的手机号是微信绑定的手机号，不需要进行短信验证。
     *
     * @param jsonObject
     * @return
     */
    @MPAccessToken
    @ApiOperation("小程序使用手机号登录")
    @PostMapping("/mpLogin")
    public Result<JSONObject> mpLogin(@RequestBody JSONObject jsonObject) {
        Result<JSONObject> result = new Result<>();
        String accessToken;
        if (Boolean.TRUE.equals(redisTemplate.hasKey(MPConstant.ACCESS_TOKEN_KEY))) {
            accessToken = redisTemplate.opsForValue().get(MPConstant.ACCESS_TOKEN_KEY) + "";
        } else {
            return result.error500("token失效");
        }
        JSONObject aaa = new JSONObject();
        aaa.put("code", jsonObject.getString("code"));
        HttpRequest post = HttpUtil.createPost(String.format("https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s", accessToken));
        post.body(aaa.toString(), ContentType.JSON.getValue());
        HttpResponse execute = post.execute();
        int status = execute.getStatus();

        String phone;

        if (status >= 200 && status < 300) {
            JSONObject res = JSON.parseObject(execute.body());
            Integer errcode = res.getInteger("errcode");
            if (errcode == 0) {
                phone = res.getJSONObject("phone_info").getString("purePhoneNumber");
            } else {
                return result.error500(res.getString("errmsg"));
            }
        } else {
            return result.error500("获取用户手机号失败");
        }

        //校验用户有效性
        SysUsers sysUser = sysUserService.getUserByPhone(phone);
        result = sysUserService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }

        //用户信息
        userInfo(sysUser, result, null, null);
        JSONObject res = (JSONObject) result.getResult();
        res.remove("sysAllDictItems");
        res.remove("multi_depart");
        //添加日志
        baseCommonService.addLog("用户名: " + sysUser.getUsername() + ",登录成功！", CommonConstant.LOG_TYPE_1, null);
        return result;
    }

    /**
     * 用户信息
     *
     * @param sysUser
     * @param result
     * @return
     */
    private void userInfo(SysUsers sysUser, Result<JSONObject> result, UmpPwdManage allPwdManage, Integer platformType) {
        String syspassword = sysUser.getPassword();
        String username = sysUser.getUsername();
        // 生成token
        String token = jwtUtil.sign(username, syspassword);
        // 设置token缓存有效时间
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, jwtUtil.getTime());
        // 获取用户部门信息
        JSONObject obj = new JSONObject();
        if (platformType != null) {
            obj.put("platformType", platformType);
        }
        obj.put("token", token);
        List<SysDepart> departs = sysDepartService.queryUserDeparts(sysUser.getId());
        obj.put("departs", departs);
        int multi_depart;
        if (CollUtil.isEmpty(departs)) {
            multi_depart = 0;
        } else if (departs.size() == 1) {
            multi_depart = 1;
            sysUserService.updateUserDepart(username, departs.get(0).getOrgCode());
        } else {
            multi_depart = 2;
            Optional<Object> optional = Optional.ofNullable(cacheUtils.getValueByKey(CommonConstant.DATA_DICT_KEY + "login_setting_choose_depart"));
            boolean chooseDepart = Integer.parseInt(String.valueOf(optional.orElse("0"))) == 1;
            if (!chooseDepart) {
                sysUserService.updateUserDepart(username, departs.get(0).getOrgCode());
                multi_depart = 0;
            } else {
                //查询当前是否有登录部门
                // update-begin--Author:wangshuai Date:20200805 for：如果用戶为选择部门，数据库为存在上一次登录部门，则取一条存进去
                SysUsers sysUserById = sysUserService.getById(sysUser.getId());
                if (oConvertUtils.isEmpty(sysUserById.getOrgCode())) {
                    sysUserService.updateUserDepart(username, departs.get(0).getOrgCode());
                }
                // update-end--Author:wangshuai Date:20200805 for：如果用戶为选择部门，数据库为存在上一次登录部门，则取一条存进去
            }
        }

        obj.put("multi_depart", multi_depart);
        //用户登录超时时候，提示修改密码
        if (allPwdManage != null && !getUpdateTime(allPwdManage, sysUser.getUsername())) {
            obj.put("multi_depart", 3);
            obj.remove("token");
        }
        List<JSONObject> roleList = sysBaseAPI.getRoleByUsername(sysUser.getUsername());
        if (CollUtil.isNotEmpty(roleList)) {
            sysUser.setRoleName(roleList.stream().map(item -> item.getString("roleName")).collect(Collectors.joining(",")));
            sysUser.setRoleCodes(roleList.stream().map(item -> item.getString("roleCode")).collect(Collectors.joining(",")));
        }
        obj.put("userInfo", sysUser);
        obj.put("sysAllDictItems", sysDictService.queryAllDictItems());
        result.setResult(obj);
        result.success("登录成功");
    }

    /**
     * ukey不需要校验密码过期
     *
     * @param sysUser
     * @param result
     * @param allPwdManage
     * @return
     */
    private Result<JSONObject> UkeyuserInfo(SysUsers sysUser, Result<JSONObject> result, UmpPwdManage allPwdManage) {
        String syspassword = sysUser.getPassword();
        String username = sysUser.getUsername();
        // 生成token
        String token = jwtUtil.sign(username, syspassword);
        // 设置token缓存有效时间
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, jwtUtil.getTime());
        // 获取用户部门信息
        JSONObject obj = new JSONObject();
        obj.put("token", token);
        List<SysDepart> departs = sysDepartService.queryUserDeparts(sysUser.getId());
        obj.put("departs", departs);


        // todo此处做调整  ,用户登录超时时候，提示修改密码
        if (!Ukey(allPwdManage, sysUser.getUsername())) {
            obj.put("multi_depart", 3);
            obj.remove("token");
        }

        if (departs == null || departs.size() == 0) {
            obj.put("multi_depart", 0);
        } else if (departs.size() == 1) {
            sysUserService.updateUserDepart(username, departs.get(0).getOrgCode());
            obj.put("multi_depart", 1);
        } else {
            //查询当前是否有登录部门
            // update-begin--Author:wangshuai Date:20200805 for：如果用戶为选择部门，数据库为存在上一次登录部门，则取一条存进去
            SysUsers sysUserById = sysUserService.getById(sysUser.getId());
            if (oConvertUtils.isEmpty(sysUserById.getOrgCode())) {
                sysUserService.updateUserDepart(username, departs.get(0).getOrgCode());
            }
            // update-end--Author:wangshuai Date:20200805 for：如果用戶为选择部门，数据库为存在上一次登录部门，则取一条存进去
            obj.put("multi_depart", 2);
        }


        // todo此处做调整  ,用户登录超时时候，提示修改密码
        if (!Ukey(allPwdManage, sysUser.getUsername())) {
            obj.put("multi_depart", 3);
            obj.remove("token");
        }

        sysUser.setRoleCodes(sysBaseAPI.getRoleCodeByUsername(sysUser.getUsername()).stream().collect(Collectors.joining(",")));
        obj.put("userInfo", sysUser);
        obj.put("sysAllDictItems", sysDictService.queryAllDictItems());
        result.setResult(obj);
        result.success("登录成功");
        return result;
    }

    /**
     * 获取加密字符串
     *
     * @return
     */
    @GetMapping(value = "/getEncryptedString")
    public Result<Map<String, String>> getEncryptedString() {
        Result<Map<String, String>> result = new Result<Map<String, String>>();
        Map<String, String> map = new HashMap<String, String>();
        map.put("key", EncryptedString.key);
        map.put("iv", EncryptedString.iv);
        result.setResult(map);
        return result;
    }

    /**
     * 后台生成图形验证码 ：有效
     *
     * @param key
     */
    @ApiOperation("获取验证码")
    @GetMapping(value = "/randomImage/{key}")
    public Result<String> randomImage(@PathVariable String key
            , @RequestParam(required = false) Integer backColor
            , @RequestParam(required = false) Integer fontColor) {
        Result<String> res = new Result<String>();
        try {
            if (key == null) {
                res.error500("key不能为空");
                return res;
            }
            String code = RandomUtil.randomString(BASE_CHECK_CODES, 4);
            String lowerCaseCode = code.toLowerCase();
            String realKey = MD5Util.MD5Encode(lowerCaseCode + key, "utf-8");
            redisUtil.set(realKey, lowerCaseCode, 60);
            String base64 = RandImageUtil.generate(code, backColor, fontColor);
            res.setSuccess(true);
            res.setResult(base64);
        } catch (Exception e) {
            res.error500("获取验证码出错" + e.getMessage());
            e.printStackTrace();
        }
        return res;
    }


    /**
     * app登录
     *
     * @param sysLoginModel
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/mLogin", method = RequestMethod.POST)
    public Result<JSONObject> mLogin(@RequestBody SysLoginModel sysLoginModel) {
        Result<JSONObject> result = new Result<JSONObject>();
        String username = sysLoginModel.getUsername();
        String password = sysLoginModel.getPassword();

        //1. 校验用户是否有效
        SysUsers sysUser = sysUserService.getUserByName(username);
        result = sysUserService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }

        //2. 校验用户名或密码是否正确
        String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
        String syspassword = sysUser.getPassword();
        if (!syspassword.equals(userpassword)) {
            result.error500("用户名或密码错误");
            return result;
        }

        String orgCode = sysUser.getOrgCode();
        if (oConvertUtils.isEmpty(orgCode)) {
            //如果当前用户无选择部门 查看部门关联信息
            List<SysDepart> departs = sysDepartService.queryUserDeparts(sysUser.getId());
            if (departs == null || departs.size() == 0) {
                result.error500("用户暂未归属部门,不可登录!");
                return result;
            }
            orgCode = departs.get(0).getOrgCode();
            sysUser.setOrgCode(orgCode);
            this.sysUserService.updateUserDepart(username, orgCode);
        }
        JSONObject obj = new JSONObject();
        //用户登录信息
        obj.put("userInfo", sysUser);

        // 生成token
        String token = jwtUtil.sign(username, syspassword);
        // 设置超时时间
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, jwtUtil.getTime());

        //token 信息
        obj.put("token", token);
        result.setResult(obj);
        result.setSuccess(true);
        result.setCode(200);
        baseCommonService.addLog("用户名: " + username + ",登录成功[移动端]！", CommonConstant.LOG_TYPE_1, null);
        return result;
    }

    /**
     * 图形验证码
     *
     * @param sysLoginModel
     * @return
     */
    @RequestMapping(value = "/checkCaptcha", method = RequestMethod.POST)
    public Result<?> checkCaptcha(@RequestBody SysLoginModel sysLoginModel) {
        String captcha = sysLoginModel.getCaptcha();
        String checkKey = sysLoginModel.getCheckKey();
        if (captcha == null) {
            return Result.error("验证码无效");
        }
        String lowerCaseCaptcha = captcha.toLowerCase();
        String realKey = MD5Util.MD5Encode(lowerCaseCaptcha + checkKey, "utf-8");
        Object checkCode = redisUtil.get(realKey);
        if (checkCode == null || !checkCode.equals(lowerCaseCaptcha)) {
            return Result.error("验证码错误");
        }
        return Result.ok();
    }

    public static final String LOCAL_IP_V6 = "0:0:0:0:0:0:0:1";
    // 获取前端ip地址
    private String getIp(HttpServletRequest request) {
        List<String> ipHeadList = Stream.of("X-Forwarded-For", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "X-Real-IP").collect(Collectors.toList());
        for (String ipHead : ipHeadList) {
            if (checkIP(request.getHeader(ipHead))) {
                return request.getHeader(ipHead).split(",")[0];
            }
        }
        return LOCAL_IP_V6.equals(request.getRemoteAddr()) ? CommonConstant.LOCAL_IP : request.getRemoteAddr();

    }

    /**
     * 检查ip存在
     */
    private boolean checkIP(String ip) {
        return !(null == ip || 0 == ip.length() || "unknown".equalsIgnoreCase(ip));
    }


    /**
     * 判断IP是否在指定IP段内，方法一（推荐）
     * ipRange IP段（以'-'分隔）
     *
     * @param ipRange
     * @param ip
     * @return boolean
     */
    public static boolean ipIsInRange(String ip, String ipRange) {
        if (ipRange == null)
            throw new NullPointerException("IP段不能为空！");
        if (ip == null)
            throw new NullPointerException("IP不能为空！");
        ipRange = ipRange.trim();
        ip = ip.trim();
        final String REGX_IP = "((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
        final String REGX_IPB = REGX_IP + "\\-" + REGX_IP;
        if (!ipRange.matches(REGX_IPB) || !ip.matches(REGX_IP))
            return false;
        int idx = ipRange.indexOf('-');
        String[] sips = ipRange.substring(0, idx).split("\\.");
        String[] sipe = ipRange.substring(idx + 1).split("\\.");
        String[] sipt = ip.split("\\.");
        long ips = 0L, ipe = 0L, ipt = 0L;
        for (int i = 0; i < 4; ++i) {
            ips = ips << 8 | Integer.parseInt(sips[i]);
            ipe = ipe << 8 | Integer.parseInt(sipe[i]);
            ipt = ipt << 8 | Integer.parseInt(sipt[i]);
        }
        if (ips > ipe) {
            long t = ips;
            ips = ipe;
            ipe = t;
        }
        return ips <= ipt && ipt <= ipe;
    }


    /**
     * 获取mac地址
     *
     * @param ip
     * @return
     * @throws UnknownHostException
     * @throws SocketException
     */
    public static String getMac(String ip) throws UnknownHostException, SocketException {


        System.out.println(ip);

        InetAddress byName = InetAddress.getByName(ip);

        System.out.println("----------" + byName);

        byte[] mac = NetworkInterface.getByInetAddress(InetAddress.getByName(ip)).getHardwareAddress();
        StringBuilder sb = new StringBuilder("");
        for (int i = 0; i < mac.length; i++) {
            if (i != 0) {
                sb.append('-');
            }
            //字节转换为整数
            int temp = mac[i] & 0xff;
            String str = Integer.toHexString(temp);
            //System.out.println("每8位:"+str);
            if (str.length() == 1) {
                sb.append("0" + str);
            } else {
                sb.append(str);
            }
        }
        return sb.toString().toUpperCase();
    }


    @RequestMapping(value = "/saveMenu")
    public Result<JSONObject> saveMenu(HttpServletRequest request, @RequestBody LoginUser loginUser) throws UnknownHostException {

        LoginUser loginUser1 = (LoginUser) SecurityUtils.getSubject().getPrincipal();

        String ip = this.getIp(request);
        if (CommonConstant.LOCAL_IP.equals(ip)) {
            InetAddress addr = InetAddress.getLocalHost();
            ip = addr.getHostAddress();
        }
        SysLog sysLog = new SysLog();
        sysLog.setIp(ip);
        sysLog.setLogType(2);
        sysLog.setUserid(loginUser1.getUsername());
        sysLog.setUsername(loginUser1.getRealname());
        sysLog.setLogContent("访问菜单：" + loginUser.getMenu());
        sysLog.setOperateResult("成功");
        boolean save = logService.save(sysLog);
        Result<JSONObject> result = new Result<JSONObject>();
        if (save) {
            result.setResult("成功");
            result.setSuccess(true);
            result.setCode(200);
        } else {
            result.setResult("失败");
            result.setSuccess(false);
            result.setCode(500);
        }
        return result;
    }


    @ApiOperation("Ukey登录获取")
    @RequestMapping(value = "/LoginRandom", method = RequestMethod.POST)
    public Result<?> login1(HttpServletRequest request) {
        ip = (String) cacheUtils.getValueByKey(CommonConstant.DATA_DICT_KEY + "UKey_ip");
        post = (String) cacheUtils.getValueByKey(CommonConstant.DATA_DICT_KEY + "UKey_port");

        if (ip == null || post == null) {
            return Result.error("缺少IP或端口配置");
        }

        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        String url = "http://" + ip + ":" + post + "/GeneratorChallenge";

        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");
        CloseableHttpResponse response = null;
        String key = null;
        try {
            response = httpClient.execute(httpPost);
            if (response == null || response.getEntity() == null){
                return Result.error("连接异常!");
            }
            HttpEntity responseEntity = response.getEntity();

            log.info("Ukey响应状态为:" + response.getStatusLine());
            if (responseEntity != null) {
                key = EntityUtils.toString(responseEntity);
                log.info("Ukey响应内容为:" + key);
            }
            return Result.OK(key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return Result.error("连接异常!");
    }

    @ApiOperation("登录接口")
    @RequestMapping(value = "/UkeyLogin", method = RequestMethod.POST)
    public Result<?> login2(@RequestBody UkeyVo ukeyVo, HttpServletRequest request) {
        ip = (String) cacheUtils.getValueByKey(CommonConstant.DATA_DICT_KEY + "UKey_ip");
        post = (String) cacheUtils.getValueByKey(CommonConstant.DATA_DICT_KEY + "UKey_port");

        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        String url = "http://" + ip + ":" + post + "/VerifyIdentityTicket";

        HttpPost httpPost = new HttpPost(url);

        StringEntity entity = new StringEntity(ukeyVo.getXmlString(), "UTF-8");
        httpPost.setEntity(entity);
        httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");
        CloseableHttpResponse response = null;
        String key = null;
        try {
            // 由客户端执行(发送)Post请求
            response = httpClient.execute(httpPost);
            // 从响应模型中获取响应实体
            HttpEntity responseEntity = response.getEntity();
            log.info("票据验证状态为:" + response.getStatusLine());
            if (responseEntity != null) {
                key = EntityUtils.toString(responseEntity);
            }
            Document document = DocumentHelper.parseText(key);
            Element root = document.getRootElement();
            Element identityticket = root.element("result");
            //解码
            String decode = Base64Util.decode(identityticket.getStringValue());
            log.info("解码后得到的xml:" + decode);
            Document document1 = DocumentHelper.parseText(decode);
            Element rootElement = document1.getRootElement();
            String result = rootElement.element("result").getStringValue();
            log.info("解码后得到的result值:" + result);
//            应用首先判断<result>元素值，0成功，非0失败；
//              成功时，直接解析出<userinfo>下的rmsid值，该值为用户在资源系统中的用户标识。
//              失败时，可从<error>元素值获取到错误原因。
            String error = rootElement.element("error").getStringValue();
            if ("1".equals(result)) {
                return Result.error(error);
            }
            Element userinfo = rootElement.element("userinfo");
            //获取到用户标识
            String rmsid = userinfo.element("rmsid").getStringValue();
            log.info("解码后得到的rmsid值:" + rmsid);
            SysUsers user = sysUserService.getById(rmsid);
            if (null != user && user.getDelFlag() == 0) {
                //存在正常登录
                return getLoginRes(request, user.getId());
            } else {
                //不存在登录失败
                return Result.error(error);
            }


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                // 释放资源
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return Result.error("登录失败");
    }

    private Result<?> getLoginRes(HttpServletRequest request, String userId) throws UnknownHostException, ParseException {
        SysUsers sysUser = sysUserService.getById(userId);
        Result<JSONObject> result = new Result<JSONObject>();
        UmpPwdManage allPwdManage = umpPwdManageMapper.findAllPwdManage();   // 此处查出该系统的所有规则
        int count = 1;
        String ip = getIp(request);
        if (CommonConstant.LOCAL_IP.equals(ip)) {
            InetAddress addr = InetAddress.getLocalHost();
            ip = addr.getHostAddress();
        }
        if (StringUtils.isNotEmpty(allPwdManage.getStartIp()) && StringUtils.isNotEmpty(allPwdManage.getStopIp())) {
            String ipParagraph = allPwdManage.getStartIp() + "-" + allPwdManage.getStopIp();
            if (!ipIsInRange(ip, ipParagraph)) {
                result.error500("不在可登录的ip范围内");
                return result;
            }
        }
        if (StringUtils.isNotEmpty(allPwdManage.getStartTime()) && StringUtils.isNotEmpty(allPwdManage.getStopTime())) {
            if (!getLoginTime(allPwdManage)) {
                result.error500("不在可登录的时间范围内");
                return result;
            }
        }
        if (allPwdManage != null) {
            if (count >= Integer.parseInt(allPwdManage.getErrorNum())) {
                Date currentTime = new Date();
                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String dateString = formatter.format(currentTime);
                sysUserMapper.updateLock(1, dateString, sysUser.getUsername());
            }
            SysUsers user = sysUserService.getOne(new QueryWrapper<SysUsers>().eq("username", sysUser.getUsername()));
            if (null == user) {
                result.error500("用户不存在");
                return result;
            } else if (user.getLocks() == 1) {
                result.error500("用户已被锁定，将在" + allPwdManage.getUnLock() + "分钟后自动解锁，或者联系安全保密管理员解锁");
                return result;
            }
        }
        //用户登录信息
        Result<JSONObject> jsonObjectResult = UkeyuserInfo(sysUser, result, allPwdManage);
        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(sysUser, loginUser);
        JSONObject result1 = (JSONObject) jsonObjectResult.getResult();
        String multi_depart = result1.getString("multi_depart");
        if (!multi_depart.equals("3")) {
            baseCommonService.addLog("用户名: " + loginUser.getRealname() + ",登录成功！", CommonConstant.LOG_TYPE_1, null, loginUser);
        }
        return result;
    }

    @ApiOperation("新疆兵团Ukey登录接口")
    @PostMapping(value = "/XJBTLogin")
    public Result<?> XJBTLogin(@RequestBody Map<String, String> data) {
        cn.hutool.json.JSONObject userInfo = XML.toJSONObject(data.get("userInfoXml"));
        final String userId = userInfo.getStr("uri");
        return getSingleSignOnToken(userId);
    }

    @ApiOperation("深圳Ukey登录接口")
    @PostMapping(value = "/SZUKeyLogin")
    public Result<?> SXFUKeyLogin(@RequestBody Map<String, String> data) {
        cn.hutool.json.JSONObject userInfo = XML.toJSONObject(data.get("userInfoXml"));
        final String userId = userInfo.getStr("uri");
        return getSingleSignOnToken(userId);
    }

    @ApiOperation("ZY登录接口")
    @GetMapping(value = "/zyLogin")
    public Result<?> zyLogin(@RequestParam("access_token") String accessToken, HttpServletRequest request) {
        final String address = String.valueOf(Optional.of(cacheUtils.getValueByKey(CommonConstant.DATA_DICT_KEY + "zySettings_address")).get());
        final String ssoUser = String.valueOf(Optional.of(cacheUtils.getValueByKey(CommonConstant.DATA_DICT_KEY + "zySettings_ssoUser")).get());
        log.info("zyLogin ----> url: {}{}", address, ssoUser);
        log.info("zyLogin ----> header: client_ip={}", request.getRemoteAddr());
        log.info("zyLogin ----> accessToken: {}", accessToken);
        final String body = HttpRequest.post(String.format(ssoUser, address))
                .header("client_ip", request.getRemoteAddr())
                .form("access_token", accessToken)
                .execute().body();
        log.info("zyLogin ----> response: {}", body);
        JSONObject userInfo = JSON.parseObject(body);
        if (!userInfo.getString("rsltcode").equals("0")) {
            return Result.OK().error500(userInfo.getString("rsltmsg"));
        }
        log.info("zyLogin ----> userInfo: {}", userInfo);
        final String userid = userInfo.getString("userId").replace("-", "");
        return getSingleSignOnToken(userid);
    }

    @ApiOperation("HK单点登录")
    @GetMapping(value = "/hkLogin")
    public Result<?> hkLogin(@RequestParam String code) {
        String apiAddress = String.valueOf(Optional.ofNullable(cacheUtils.getValueByKey(CommonConstant.DATA_DICT_KEY + "ZJGSettings_address")).orElse(""));

        String accessToken = "";
        if (redisUtil.hasKey(CommonConstant.ZJG_TOKEN)) {
            //从缓存中获取access-token
            accessToken = String.valueOf(redisUtil.get(CommonConstant.ZJG_TOKEN));
        } else {
            //
            String clientId = String.valueOf(Optional.ofNullable(cacheUtils.getValueByKey(CommonConstant.DATA_DICT_KEY + "ZJGSettings_clientId")).orElse(""));
            String clientSecret = String.valueOf(Optional.ofNullable(cacheUtils.getValueByKey(CommonConstant.DATA_DICT_KEY + "ZJGSettings_clientSecret")).orElse(""));
            String geTokenValueApi = String.valueOf(Optional.ofNullable(cacheUtils.getValueByKey(CommonConstant.DATA_DICT_KEY + "ZJGSettings_geTokenValue")).orElse(""));

            Assert.notBlank(apiAddress, "[api地址获取失败] - this String argument must have text; it must not be null, empty, or blank");
            Assert.notBlank(clientId, "[应用id获取失败] - this String argument must have text; it must not be null, empty, or blank");
            Assert.notBlank(clientSecret, "[应用密钥获取失败] - this String argument must have text; it must not be null, empty, or blank");

            final String res = HttpUtil.get(String.format("%s%s?grant_type=authorization_code&client_id=%s&client_secret=%s&code=%s", apiAddress, geTokenValueApi, clientId, clientSecret, code));

            JSONObject tokenValue = JSON.parseObject(res);
            if (200 == tokenValue.getInteger("code")) {
                log.info("获取access_token: {}", JSON.toJSONString(tokenValue, true));
                final JSONObject data = tokenValue.getJSONObject("data");
                accessToken = data.getString("access_token");
                final Integer expiresIn = data.getInteger("expires_in");
                redisUtil.set(CommonConstant.ZJG_TOKEN, accessToken, expiresIn - 200);
            }
        }
        if (StringUtils.isNotEmpty(accessToken)) {
            String ssoUserinfoApi = String.valueOf(Optional.ofNullable(cacheUtils.getValueByKey(CommonConstant.DATA_DICT_KEY + "ZJGSettings_ssoUserinfo")).orElse(""));

            final HttpRequest postRequest = HttpUtil.createPost(String.format("%s%s", apiAddress, ssoUserinfoApi));
            JSONObject requestBody = new JSONObject();
            requestBody.put("access_token", accessToken);
            postRequest.body(requestBody.toJSONString(), ContentType.JSON.getValue());
            final String response = postRequest.execute().body();
            JSONObject userinfo = JSON.parseObject(response);
            SysUsers sysUser = new SysUsers();
            log.info("获取userinfo: {}", JSON.toJSONString(userinfo, true));
            if (200 == userinfo.getInteger("code")) {
                String username = userinfo.getJSONObject("data").getString("username");
                sysUser = sysUserService.getUserByName(username);
            }
            return getSingleSignOnToken(sysUser.getId());
        } else {
            return Result.error("accessToken获取异常");
        }

    }

    private Result<?> getSingleSignOnToken(String userId) {
        SysUsers sysUser = sysUserService.getById(userId);
        if (null == sysUser) {
            return Result.OK().error500("用户不存在");
        }
        List<JSONObject> roleList = sysBaseAPI.getRoleByUsername(sysUser.getUsername());
        if (CollUtil.isNotEmpty(roleList)) {
            sysUser.setRoleName(roleList.stream().map(item -> item.getString("roleName")).collect(Collectors.joining(",")));
            sysUser.setRoleCodes(roleList.stream().map(item -> item.getString("roleCode")).collect(Collectors.joining(",")));
        } else {
            return Result.OK().error500("用户无访问权限");
        }
        // 生成token
        String token = jwtUtil.sign(sysUser.getUsername(), sysUser.getPassword());
        // 设置token缓存有效时间
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, jwtUtil.getTime());
        JSONObject obj = new JSONObject();
        obj.put("token", token);
        obj.put("userInfo", sysUser);
        obj.put("sysAllDictItems", sysDictService.queryAllDictItems());
        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(sysUser, loginUser);
        baseCommonService.addLog("用户名: " + loginUser.getRealname() + ",登录成功！", CommonConstant.LOG_TYPE_1, null, loginUser);
        return Result.OK("登录成功", obj);
    }

    private boolean isOnline(String username) {
        boolean f = false;
        Set<String> keys = redisUtil.keys(com.insight.common.constant.CommonConstant.PREFIX_USER_TOKEN + "*");
        for (String key : keys) {
            String token = (String) redisUtil.get(key);
            if (StringUtils.isNotEmpty(token) && username.equals(JwtUtil.getUsername(token))) {
                f = true;
                break;
            }
        }
        return f;
    }
}


